#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include "server.h"

#define MAXCLIENTS 1

void catch_int(int sig_num)
{
  printf("SIGNAL HANDLER CALLED!\n");
}

static server_info_t server;               /* Server info structure */

ssize_t                         /* Read "n" bytes from a descriptor. */
readn(int fd, void *vptr, size_t n)
{
    size_t  nleft;
    ssize_t nread;
    char   *ptr;

    ptr = (char*)vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;      /* and call read() again */
            else
                return (-1);
        } else if (nread == 0)
            break;              /* EOF */

        nleft -= nread;
        ptr += nread;
    }
    return (n - nleft);         /* return >= 0 */
}

ssize_t                         /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;

    ptr = (char*)vptr;
    nleft = n;
    while (nleft > 0) {
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;   /* and call write() again */
            else
                return (-1);    /* error */
         }

         nleft -= nwritten;
         ptr += nwritten;
    }
    return (n);
}

int start_server(int port)
{
  struct sockaddr_in my_addr;

  server.started=0;
  printf("Starting CAN Server...\n");
  memset(&server,0,sizeof(server_info_t));

  // Create TCP Socket
  my_addr.sin_family      = AF_INET;
  my_addr.sin_port        = htons(port);
  my_addr.sin_addr.s_addr = INADDR_ANY;
  server.sockfd=socket(PF_INET,SOCK_STREAM,0);    /* create socket fd       */
  if (server.sockfd == -1)
  {
     perror("socket");
     return -1;
  }

  signal(SIGPIPE, catch_int);

  int reuse_option=1;
  if (setsockopt (server.sockfd,
                  SOL_SOCKET,
                  SO_REUSEADDR,
                  &reuse_option,
                  sizeof (reuse_option)) < 0)
  {
    perror("setsockopt");
    return -1;
  }

  if (bind(server.sockfd, (const struct sockaddr*)&my_addr,
           sizeof(struct sockaddr_in)) <0 )
  {
    perror("bind");
    return -1;
  }

  if (listen(server.sockfd, MAXCLIENTS) == -1)
  {
    perror("listen");
    return -1;
  }

  server.started=1;
  return 0;
}

int stop_server(void)
{
  if (server.started != 1)
  {
     return 1;
  }
  close(server.sockfd);
  return 0;
}

server_info_t get_serverinfo(void)
{
  return server;
}
